import React, { useCallback, useEffect, useRef } from 'react';
import { isMacOS } from '@copilotkit/shared';
import { useChatContext, WindowProps } from '@copilotkit/react-ui';
import { ShadowDOMManager } from '../isolation/ShadowDOMManager';

interface ShadowedWindowProps extends WindowProps {
  shadowManager?: ShadowDOMManager;
}

/**
 * 检查点击是否在窗口外部
 */
const useClickOutsideDetection = (
  windowRef: React.RefObject<HTMLDivElement>,
  shadowManager?: ShadowDOMManager
) => {
  return useCallback(
    (event: MouseEvent, target: HTMLElement): boolean => {
      // 检查点击目标的className，防止关闭调试菜单时关闭窗口
      const className = target.className || '';
      if (className.includes('copilotKitDebugMenu')) {
        return false; // 不关闭窗口
      }

      // 如果有shadowManager，检查点击是否在Shadow DOM容器内
      if (!shadowManager) {
        return true;
      }

      try {
        const containerElement = shadowManager.getContainer();
        if (containerElement) {
          // 如果点击在Shadow DOM容器外部，应该关闭窗口
          const isClickOutsideContainer =
            !containerElement.contains(target) && containerElement !== target;
          return isClickOutsideContainer;
        }
      } catch (error) {
        console.warn('Error checking shadow DOM container:', error);
      }

      return true;
    },
    [shadowManager]
  );
};

/**
 * 移动端适配hook
 */
const useMobileAdaptation = (windowRef: React.RefObject<HTMLDivElement>, open: boolean) => {
  return useCallback(() => {
    const copilotKitWindow = windowRef.current;
    const vv = window.visualViewport;
    if (!copilotKitWindow || !vv) {
      return;
    }

    if (window.innerWidth < 640 && open) {
      copilotKitWindow.style.height = `${vv.height}px`;
      copilotKitWindow.style.left = `${vv.offsetLeft}px`;
      copilotKitWindow.style.top = `${vv.offsetTop}px`;

      document.body.style.position = 'fixed';
      document.body.style.width = '100%';
      document.body.style.height = `${window.innerHeight}px`;
      document.body.style.overflow = 'hidden';
      document.body.style.touchAction = 'none';

      // Prevent scrolling on iOS
      document.body.addEventListener('touchmove', preventScroll, {
        passive: false,
      });
    } else {
      copilotKitWindow.style.height = '';
      copilotKitWindow.style.left = '';
      copilotKitWindow.style.top = '';
      document.body.style.position = '';
      document.body.style.height = '';
      document.body.style.width = '';
      document.body.style.overflow = '';
      document.body.style.top = '';
      document.body.style.touchAction = '';

      document.body.removeEventListener('touchmove', preventScroll);
    }
  }, [open, windowRef]);
};

/**
 * 事件监听器设置hook
 */
const useEventListeners = (
  handleClickOutside: (event: MouseEvent) => void,
  handleKeyDown: (event: KeyboardEvent) => void,
  adjustForMobile: () => void,
  shadowManager?: ShadowDOMManager
) => {
  useEffect(() => {
    // 获取当前文档
    const currentDocument = document;

    // 在当前文档（Shadow DOM内部）监听事件
    currentDocument.addEventListener('mousedown', handleClickOutside);
    currentDocument.addEventListener('keydown', handleKeyDown);

    // 如果有shadowManager，使用它来获取宿主文档并监听事件
    let hostDocument: Document | null = null;
    if (shadowManager) {
      hostDocument = shadowManager.getHostDocument();
      if (hostDocument && hostDocument !== currentDocument) {
        hostDocument.addEventListener('mousedown', handleClickOutside);
        hostDocument.addEventListener('keydown', handleKeyDown);
      }
    } else {
      // 备用方案：尝试获取宿主文档
      const fallbackHostDocument = currentDocument.defaultView?.parent?.document || currentDocument;
      if (fallbackHostDocument !== currentDocument) {
        hostDocument = fallbackHostDocument;
        hostDocument.addEventListener('mousedown', handleClickOutside);
        hostDocument.addEventListener('keydown', handleKeyDown);
      }
    }

    if (window.visualViewport) {
      window.visualViewport.addEventListener('resize', adjustForMobile);
      adjustForMobile();
    }

    return () => {
      // 清理当前文档的事件监听器
      currentDocument.removeEventListener('mousedown', handleClickOutside);
      currentDocument.removeEventListener('keydown', handleKeyDown);

      // 清理宿主文档的事件监听器
      if (hostDocument && hostDocument !== currentDocument) {
        hostDocument.removeEventListener('mousedown', handleClickOutside);
        hostDocument.removeEventListener('keydown', handleKeyDown);
      }

      if (window.visualViewport) {
        window.visualViewport.removeEventListener('resize', adjustForMobile);
      }
    };
  }, [adjustForMobile, handleClickOutside, handleKeyDown, shadowManager]);
};

export const ShadowedWindow = ({
  children,
  clickOutsideToClose,
  shortcut,
  hitEscapeToClose,
  shadowManager,
}: ShadowedWindowProps) => {
  const windowRef = useRef<HTMLDivElement>(null);
  const { open, setOpen } = useChatContext();

  // 使用自定义hooks
  const detectClickOutside = useClickOutsideDetection(windowRef, shadowManager);
  const adjustForMobile = useMobileAdaptation(windowRef, open);

  const handleClickOutside = useCallback(
    (event: MouseEvent) => {
      if (!clickOutsideToClose || !open) {
        return;
      }

      const windowElement = windowRef.current;
      if (!windowElement) {
        return;
      }

      // 获取事件目标
      const target = event.target as HTMLElement;
      if (!target) {
        return;
      }

      // 使用提取的点击检测逻辑
      const shouldCloseWindow = detectClickOutside(event, target);
      if (shouldCloseWindow) {
        setOpen(false);
      }
    },
    [clickOutsideToClose, open, setOpen, detectClickOutside, windowRef]
  );

  const handleKeyDown = useCallback(
    (event: KeyboardEvent) => {
      const target = event.target as HTMLElement;
      const isInput =
        target.tagName === 'INPUT' ||
        target.tagName === 'SELECT' ||
        target.tagName === 'TEXTAREA' ||
        target.isContentEditable;

      const isDescendantOfWrapper = windowRef.current?.contains(target);

      if (
        open &&
        event.key === 'Escape' &&
        (!isInput || isDescendantOfWrapper) &&
        hitEscapeToClose
      ) {
        setOpen(false);
      } else if (
        event.key === shortcut &&
        ((isMacOS() && event.metaKey) || (!isMacOS() && event.ctrlKey)) &&
        (!isInput || isDescendantOfWrapper)
      ) {
        setOpen(!open);
      }
    },
    [hitEscapeToClose, shortcut, open, setOpen]
  );

  // 使用事件监听器hook
  useEventListeners(handleClickOutside, handleKeyDown, adjustForMobile, shadowManager);

  return (
    <div className={`copilotKitWindow ${open ? ' open' : ''}`} ref={windowRef}>
      {children}
    </div>
  );
};

const preventScroll = (event: TouchEvent): void => {
  const targetElement = event.target as Element;

  // Function to check if the target has the parent with a given class
  const hasParentWithClass = (element: Element, className: string): boolean => {
    while (element && element !== document.body) {
      if (element.classList.contains(className)) {
        return true;
      }
      element = element.parentElement!;
    }
    return false;
  };

  // Check if the target of the touch event is inside an element with the 'copilotKitMessages' class
  if (!hasParentWithClass(targetElement, 'copilotKitMessages')) {
    event.preventDefault();
  }
};
